﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RpcGenerator.AS3
{
    class AS3InvokerGenerator
    {
        public static void Generate(Type type, IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            string invokerName = RpcGeneratorHelper.GetInvokerName(type);
            serializer.NewLine(string.Format("public class {0} implements RpcInvoker", invokerName));
            serializer.BeginBlock();
                serializer.NewLine(string.Format("public static const Instance:{0} = new {0}();", invokerName));

                serializer.NewLine();
                GenerateInvoke(type, serializer, allDescriptions);

                serializer.NewLine();
                GenerateReturn(type, serializer, allDescriptions);

            serializer.EndBlock();

            string result = serializer.ToString();
            Console.WriteLine(result);
        }

        private static void GenerateInvoke(Type type, IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            serializer.NewLine("public function Invoke(_interface:*,service:RpcService,flags:int,methodid:int,stream:NetStream):void");
            serializer.BeginBlock();
            serializer.NewLine(string.Format("var _implement:{0} = _interface as {0};", type.Name));
            serializer.NewLine("switch (methodid)");
            serializer.BeginBlock();
            MessageDescriptionGenerator mdgenerator = new MessageDescriptionGenerator();
            allDescriptions = allDescriptions.Where(description => description.IsRequest == true).ToList();
            allDescriptions.ForEach(description =>
            {
                serializer.NewLine(string.Format("case {0}:", description.MethodId));
                serializer.BeginBlock();
                serializer.NewLine(string.Format("var request:{0} = new {0}();", description.Name));
                serializer.NewLine("request.Read(stream);");
                if (description.Response == null)
                {
                    serializer.NewLine(string.Format("_implement.{0}(", description.Method.Method.Name));
                }
                else
                {
                    string typeName = RpcGeneratorHelper.GetParameterTypeName(description.Response.Fields[0].Type);
                    serializer.NewLine(string.Format("var returnValue:{0} = _implement.{1}(",  typeName, description.Method.Method.Name));
                }

                if (description.Fields.Count > 0)
                {
                    MessageFieldDescription lastField = description.Fields[description.Fields.Count - 1];
                    description.Fields.ForEach(fieldDescription =>
                    {
                        if (lastField != fieldDescription)
                        {
                            serializer.Apppend(string.Format("request.{0},", fieldDescription.Name));
                        }
                        else
                        {
                            serializer.Apppend(string.Format("request.{0}", fieldDescription.Name));
                        }
                    });
                }
                serializer.Apppend(");");

                if (description.Response != null)
                {
                    serializer.NewLine();
                    serializer.NewLine(string.Format("var response:{0} = new {0}();", description.Response.Name));
                    serializer.NewLine("response.returnValue = returnValue;");
                    serializer.NewLine(string.Format("service.FromServiceReturn(response,{0});", description.NeedEncrypt ? "true" : "false"));
                }
                serializer.NewLine("break;");
                serializer.EndBlock();
            });
            serializer.EndBlock();
            serializer.EndBlock();
        }

        private static void GenerateReturn(Type type, IMessageSerializer serializer, List<MessageDescription> allDescriptions)
        {
            serializer.NewLine("public function Return(_interface:*,flags:int,methodid:int,stream:NetStream):void ");
            serializer.BeginBlock();
            serializer.NewLine(string.Format("var _implement:{0}Callback = _interface as {0}Callback;", type.Name));
            serializer.NewLine("switch (methodid)");
            serializer.BeginBlock();
            MessageDescriptionGenerator mdgenerator = new MessageDescriptionGenerator();
            allDescriptions = allDescriptions.Where(description => description.IsRequest == false).ToList();

            allDescriptions.ForEach(description =>
            {
                serializer.NewLine(string.Format("case {0}:", description.MethodId));
                serializer.BeginBlock();
                serializer.NewLine(string.Format("var response:{0} = new {0}();", description.Name));
                serializer.NewLine("response.Read(stream);");
                serializer.NewLine(string.Format("_implement.On{0}(", description.Method.Method.Name));
                if (description.Fields.Count > 0)
                {
                    serializer.Apppend("response.returnValue");
                }
                serializer.Apppend(");");
                serializer.NewLine("break;");
                serializer.EndBlock();
            });
            serializer.EndBlock();
            serializer.EndBlock();
        }
    }
}
